gskglrenderer: Optimize radial-gradient shader
authorFabio Lagalla <lagfabio@amazon.com>
Tue, 26 Jan 2021 11:32:04 +0000 (12:32 +0100)
committerFabio Lagalla <lagfabio@amazon.com>
Wed, 27 Jan 2021 11:44:10 +0000 (12:44 +0100)
gsk/gl/gskglrenderer.c
gsk/gl/gskglrenderopsprivate.h
gsk/resources/glsl/radial_gradient.glsl

index b083eac5a73ea51158934e77139875f7c37a76c2..28df34f348da1c44ee42510e810484b77b9584cb 100644 (file)
@@ -3050,6 +3050,9 @@ static inline void
 apply_radial_gradient_op (const Program          *program,
                           const OpRadialGradient *op)
 {
+  float scale;
+  float bias;
+
   OP_PRINT (" -> Radial gradient");
   if (op->n_color_stops.send)
     glUniform1i (program->radial_gradient.num_color_stops_location, op->n_color_stops.value);
@@ -3059,10 +3062,12 @@ apply_radial_gradient_op (const Program          *program,
                   op->n_color_stops.value * 5,
                   (float *)op->color_stops.value);
 
-  glUniform1f (program->radial_gradient.start_location, op->start);
-  glUniform1f (program->radial_gradient.end_location, op->end);
-  glUniform2f (program->radial_gradient.radius_location, op->radius[0], op->radius[1]);
-  glUniform2f (program->radial_gradient.center_location, op->center[0], op->center[1]);
+  scale = 1.0f / (op->end - op->start);
+  bias = -op->start * scale;
+  glUniform2f (program->radial_gradient.range_location, scale, bias);
+  glUniform4f (program->radial_gradient.geometry_location,
+               op->center[0], op->center[1],
+               1.0f / op->radius[0], 1.0f / op->radius[1]);
 }
 
 static inline void
@@ -3374,10 +3379,8 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
   /* radial gradient */
   INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, color_stops);
   INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, num_color_stops);
-  INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, center);
-  INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, start);
-  INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, end);
-  INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, radius);
+  INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, geometry);
+  INIT_PROGRAM_UNIFORM_LOCATION (radial_gradient, range);
 
   /* conic gradient */
   INIT_PROGRAM_UNIFORM_LOCATION (conic_gradient, color_stops);
index 85f62f045134d870c95bfbc6251ea495684877df..a04e1d2b0fd858d22923b561acb551b5b91f0fbc 100644 (file)
@@ -123,10 +123,8 @@ struct _Program
     struct {
       int num_color_stops_location;
       int color_stops_location;
-      int center_location;
-      int start_location;
-      int end_location;
-      int radius_location;
+      int geometry_location;
+      int range_location;
     } radial_gradient;
     struct {
       int num_color_stops_location;
index 178806f83c89d6533da451371c44e8182aba485c..9834a69ba4817d631e22d7a097c96dc2d7e8c0e9 100644 (file)
@@ -1,31 +1,18 @@
 // VERTEX_SHADER
-uniform float u_start;
-uniform float u_end;
-uniform float u_color_stops[6 * 5];
-uniform int u_num_color_stops;
-uniform vec2 u_radius;
-uniform vec2 u_center;
+uniform vec4 u_geometry;
 
-_OUT_ vec2 center;
-_OUT_ vec4 color_stops[6];
-_OUT_ float color_offsets[6];
-_OUT_ float start;
-_OUT_ float end;
+_NOPERSPECTIVE_ _OUT_ vec2 coord;
 
 void main() {
-  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
-
-  center = (u_modelview * vec4(u_center, 0, 1)).xy;
-  start = u_start;
-  end = u_end;
-
-  for (int i = 0; i < u_num_color_stops; i ++) {
-    color_offsets[i] = u_color_stops[(i * 5) + 0];
-    color_stops[i] = gsk_premultiply(vec4(u_color_stops[(i * 5) + 1],
-                                          u_color_stops[(i * 5) + 2],
-                                          u_color_stops[(i * 5) + 3],
-                                          u_color_stops[(i * 5) + 4]));
-  }
+  gl_Position = u_projection * (u_modelview * vec4(aPosition, 0.0, 1.0));
+
+  vec2 mv0 = u_modelview[0].xy;
+  vec2 mv1 = u_modelview[1].xy;
+  vec2 offset = aPosition - u_geometry.xy;
+  vec2 dir = vec2(dot(mv0, offset),
+                  dot(mv1, offset));
+
+  coord = dir * u_geometry.zw;
 }
 
 // FRAGMENT_SHADER:
@@ -35,50 +22,48 @@ uniform int u_num_color_stops;
 uniform highp int u_num_color_stops;
 #endif
 
-uniform vec2 u_radius;
-uniform float u_end;
+uniform vec2 u_range;
+uniform float u_color_stops[6 * 5];
+
+_NOPERSPECTIVE_ _IN_ vec2 coord;
+
+float get_offset(int index) {
+  return u_color_stops[5 * index];
+}
 
-_IN_ vec2 center;
-_IN_ vec4 color_stops[6];
-_IN_ float color_offsets[6];
-_IN_ float start;
-_IN_ float end;
+vec4 get_color(int index) {
+  int base = 5 * index + 1;
 
-// The offsets in the color stops are relative to the
-// start and end values of the gradient.
-float abs_offset(float offset)  {
-  return start + ((end - start) * offset);
+  return vec4(u_color_stops[base],
+              u_color_stops[base + 1],
+              u_color_stops[base + 2],
+              u_color_stops[base + 3]);
 }
 
 void main() {
-  vec2 pixel = gsk_get_frag_coord();
-  vec2 rel = (center - pixel) / (u_radius);
-  float d = sqrt(dot(rel, rel));
-
-  if (d < abs_offset (color_offsets[0])) {
-    gskSetOutputColor(color_stops[0] * u_alpha);
-    return;
-  }
+  // Reverse scale
+  float offset = length(coord) * u_range.x + u_range.y;
 
-  if (d > end) {
-    gskSetOutputColor(color_stops[u_num_color_stops - 1] * u_alpha);
+  if (offset < get_offset(0)) {
+    gskSetOutputColor(gsk_scaled_premultiply(get_color(0), u_alpha));
     return;
   }
 
-  vec4 color = vec4(0, 0, 0, 0);
-  for (int i = 1; i < u_num_color_stops; i++) {
-    float last_offset = abs_offset(color_offsets[i - 1]);
-    float this_offset = abs_offset(color_offsets[i]);
+  int n = u_num_color_stops - 1;
+  for (int i = 0; i < n; i++) {
+    float curr_offset = get_offset(i);
+    float next_offset = get_offset(i + 1);
 
-    // We have color_stops[i - 1] at last_offset and color_stops[i] at this_offset.
-    // We now need to map `d` between those two offsets and simply mix linearly between them
-    if (d >= last_offset && d <= this_offset) {
-      float f = (d - last_offset) / (this_offset - last_offset);
+    if (offset >= curr_offset && offset < next_offset) {
+      float f = (offset - curr_offset) / (next_offset - curr_offset);
+      vec4 curr_color = gsk_premultiply(get_color(i));
+      vec4 next_color = gsk_premultiply(get_color(i + 1));
+      vec4 color = mix(curr_color, next_color, f);
 
-      color = mix(color_stops[i - 1], color_stops[i], f);
-      break;
+      gskSetOutputColor(color * u_alpha);
+      return;
     }
   }
 
-  gskSetOutputColor(color * u_alpha);
+  gskSetOutputColor(gsk_scaled_premultiply(get_color(n), u_alpha));
 }